<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" lang="" xml:lang="">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
    <meta name="description" content="Interested in adding textures, lighting, shadows, normal maps, glowing objects, ambient occlusion, reflections, refractions, and more to your 3D game? Great! 3D Game Shaders For Beginners is a collection of shading techniques that will take your game visuals to new heights." />
    <meta property="og:title" content="Foam | 3D Game Shaders For Beginners" />
    <meta property="og:description" content="Interested in adding textures, lighting, shadows, normal maps, glowing objects, ambient occlusion, reflections, refractions, and more to your 3D game? Great! 3D Game Shaders For Beginners is a collection of shading techniques that will take your game visuals to new heights." />
    <meta property="og:image" content="https://i.imgur.com/JIDwVTm.png" />
    <meta name="twitter:title" content="Foam | 3D Game Shaders For Beginners" />
    <meta name="twitter:description" content="Interested in adding textures, lighting, shadows, normal maps, glowing objects, ambient occlusion, reflections, refractions, and more to your 3D game? Great! 3D Game Shaders For Beginners is a collection of shading techniques that will take your game visuals to new heights." />
    <meta name="twitter:image" content="https://i.imgur.com/JIDwVTm.png" />
    <meta name="twitter:card" content="summary_large_image" />
    <link rel="icon" type="image/x-icon" href="favicon.ico" />
    <meta name="author" content="David Lettier" />
    <title>Foam | 3D Game Shaders For Beginners</title>
    <style>
      code{white-space: pre-wrap;}
      span.smallcaps{font-variant: small-caps;}
      span.underline{text-decoration: underline;}
      div.column{display: inline-block; vertical-align: top; width: 50%;}
    </style>
    <style>
      code.sourceCode > span { display: inline-block; line-height: 1.25; }
      code.sourceCode > span { color: inherit; text-decoration: inherit; }
      code.sourceCode > span:empty { height: 1.2em; }
      .sourceCode { overflow: visible; }
      code.sourceCode { white-space: pre; position: relative; }
      div.sourceCode { margin: 1em 0; }
      pre.sourceCode { margin: 0; }
      @media screen {
      div.sourceCode { overflow: auto; }
      }
      @media print {
      code.sourceCode { white-space: pre-wrap; }
      code.sourceCode > span { text-indent: -5em; padding-left: 5em; }
      }
      pre.numberSource code
        { counter-reset: source-line 0; }
      pre.numberSource code > span
        { position: relative; left: -4em; counter-increment: source-line; }
      pre.numberSource code > span > a:first-child::before
        { content: counter(source-line);
          position: relative; left: -1em; text-align: right; vertical-align: baseline;
          border: none; display: inline-block;
          -webkit-touch-callout: none; -webkit-user-select: none;
          -khtml-user-select: none; -moz-user-select: none;
          -ms-user-select: none; user-select: none;
          padding: 0 4px; width: 4em;
          background-color: #232629;
          color: #7a7c7d;
        }
      pre.numberSource { margin-left: 3em; border-left: 1px solid #7a7c7d;  padding-left: 4px; }
      div.sourceCode
        { color: #cfcfc2; background-color: #232629; }
      @media screen {
      code.sourceCode > span > a:first-child::before { text-decoration: underline; }
      }
      code span. { color: #cfcfc2; } /* Normal */
      code span.al { color: #95da4c; } /* Alert */
      code span.an { color: #3f8058; } /* Annotation */
      code span.at { color: #2980b9; } /* Attribute */
      code span.bn { color: #f67400; } /* BaseN */
      code span.bu { color: #7f8c8d; } /* BuiltIn */
      code span.cf { color: #fdbc4b; } /* ControlFlow */
      code span.ch { color: #3daee9; } /* Char */
      code span.cn { color: #27aeae; } /* Constant */
      code span.co { color: #7a7c7d; } /* Comment */
      code span.cv { color: #7f8c8d; } /* CommentVar */
      code span.do { color: #a43340; } /* Documentation */
      code span.dt { color: #2980b9; } /* DataType */
      code span.dv { color: #f67400; } /* DecVal */
      code span.er { color: #da4453; } /* Error */
      code span.ex { color: #0099ff; } /* Extension */
      code span.fl { color: #f67400; } /* Float */
      code span.fu { color: #8e44ad; } /* Function */
      code span.im { color: #27ae60; } /* Import */
      code span.in { color: #c45b00; } /* Information */
      code span.kw { color: #cfcfc2; } /* Keyword */
      code span.op { color: #cfcfc2; } /* Operator */
      code span.ot { color: #27ae60; } /* Other */
      code span.pp { color: #27ae60; } /* Preprocessor */
      code span.re { color: #2980b9; } /* RegionMarker */
      code span.sc { color: #3daee9; } /* SpecialChar */
      code span.ss { color: #da4453; } /* SpecialString */
      code span.st { color: #f44f4f; } /* String */
      code span.va { color: #27aeae; } /* Variable */
      code span.vs { color: #da4453; } /* VerbatimString */
      code span.wa { color: #da4453; } /* Warning */
    </style>
    <!--[if lt IE 9]>
      <script src="//cdnjs.cloudflare.com/ajax/libs/html5shiv/3.7.3/html5shiv-printshiv.min.js"></script>
    <![endif]-->
    <link rel="stylesheet" href="style.css" />
  </head>
  <body>
<p><a href="screen-space-refraction.html"><span class="emoji" data-emoji="arrow_backward">◀️</span></a> <a href="index.html"><span class="emoji" data-emoji="arrow_double_up">⏫</span></a> <a href="#"><span class="emoji" data-emoji="arrow_up_small">🔼</span></a> <a href="#copyright"><span class="emoji" data-emoji="arrow_down_small">🔽</span></a> <a href="flow-mapping.html"><span class="emoji" data-emoji="arrow_forward">▶️</span></a></p>
<h1 id="3d-game-shaders-for-beginners">3D Game Shaders For Beginners</h1>
<h2 id="foam">Foam</h2>
<p align="center">
<img src="https://i.imgur.com/SVLPYKn.gif" alt="Foam" title="Foam">
</p>

<p>Foam is typically used when simulating some body of water. Anywhere the water's flow is disrupted, you add some foam. The foam isn't much by itself but it can really connect the water with the rest of the scene.</p>
<p align="center">
<img src="https://i.imgur.com/HCqvd8c.gif" alt="Lava River" title="Lava River">
</p>

<p>But don't stop at just water. You can use the same technique to make a river of lava for example.</p>
<h3 id="vertex-positions">Vertex Positions</h3>
<p>Like <a href="screen-space-refraction.html">screen space refraction</a>, you'll need both the foreground and background vertex positions. The foreground being the scene with the foamy surface and the background being the scene without the foamy surface. Referrer back to <a href="ssao.html#vertex-positions">SSAO</a> for the details on how to acquire the vertex positions in view space.</p>
<h3 id="mask">Mask</h3>
<p align="center">
<img src="https://i.imgur.com/N6TWBw8.gif" alt="Foam Mask" title="Foam Mask">
</p>

<p>You'll need to texture your scene with a foam mask. The demo masks everything off except the water. For the water, it textures it with a foam pattern.</p>
<div class="sourceCode" id="cb1"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb1-1"><a href="#cb1-1"></a><span class="co">// ...</span></span>
<span id="cb1-2"><a href="#cb1-2"></a></span>
<span id="cb1-3"><a href="#cb1-3"></a>uniform sampler2D foamPatternTexture;</span>
<span id="cb1-4"><a href="#cb1-4"></a></span>
<span id="cb1-5"><a href="#cb1-5"></a>in vec2 diffuseCoord;</span>
<span id="cb1-6"><a href="#cb1-6"></a></span>
<span id="cb1-7"><a href="#cb1-7"></a>out vec4 fragColor;</span>
<span id="cb1-8"><a href="#cb1-8"></a></span>
<span id="cb1-9"><a href="#cb1-9"></a><span class="dt">void</span> main() {</span>
<span id="cb1-10"><a href="#cb1-10"></a>  vec4 foamPattern = texture(foamPatternTexture, diffuseCoord);</span>
<span id="cb1-11"><a href="#cb1-11"></a></span>
<span id="cb1-12"><a href="#cb1-12"></a>  fragColor = vec4(vec3(dot(foamPattern.rgb, vec3(<span class="dv">1</span>)) / <span class="dv">3</span>), <span class="dv">1</span>);</span>
<span id="cb1-13"><a href="#cb1-13"></a>}</span></code></pre></div>
<p>Here you see the fragment shader that generates the foam mask. It takes a foam pattern texture and UV maps it to the scene's geometry using the diffuse UV coordinates. For every model, except the water, the shader is given a solid black texture as the <code>foamPatternTexture</code>.</p>
<div class="sourceCode" id="cb2"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb2-1"><a href="#cb2-1"></a>  <span class="co">// ...</span></span>
<span id="cb2-2"><a href="#cb2-2"></a></span>
<span id="cb2-3"><a href="#cb2-3"></a>  fragColor = vec4(vec3(dot(foamPattern.rgb, vec3(<span class="dv">1</span>)) / <span class="dv">3</span>), <span class="dv">1</span>);</span>
<span id="cb2-4"><a href="#cb2-4"></a></span>
<span id="cb2-5"><a href="#cb2-5"></a>  <span class="co">// ...</span></span></code></pre></div>
<p>The fragment color is converted to greyscale, as a precaution, since the foam shader expects the foam mask to be greyscale.</p>
<h3 id="uniforms">Uniforms</h3>
<div class="sourceCode" id="cb3"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb3-1"><a href="#cb3-1"></a><span class="co">// ...</span></span>
<span id="cb3-2"><a href="#cb3-2"></a></span>
<span id="cb3-3"><a href="#cb3-3"></a>uniform sampler2D maskTexture;</span>
<span id="cb3-4"><a href="#cb3-4"></a>uniform sampler2D positionFromTexture;</span>
<span id="cb3-5"><a href="#cb3-5"></a>uniform sampler2D positionToTexture;</span>
<span id="cb3-6"><a href="#cb3-6"></a></span>
<span id="cb3-7"><a href="#cb3-7"></a><span class="co">// ...</span></span></code></pre></div>
<p>The foam shader accepts a mask texture, the foreground vertex positions (<code>positionFromTexture</code>), and the background vertex positions (<code>positionToTexture</code>).</p>
<h3 id="parameters">Parameters</h3>
<div class="sourceCode" id="cb4"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb4-1"><a href="#cb4-1"></a>  <span class="co">// ...</span></span>
<span id="cb4-2"><a href="#cb4-2"></a></span>
<span id="cb4-3"><a href="#cb4-3"></a>  <span class="dt">float</span> foamDepth = <span class="dv">4</span>;</span>
<span id="cb4-4"><a href="#cb4-4"></a>  vec4  foamColor = vec4(<span class="fl">0.8</span>, <span class="fl">0.85</span>, <span class="fl">0.92</span>, <span class="dv">1</span>);</span>
<span id="cb4-5"><a href="#cb4-5"></a></span>
<span id="cb4-6"><a href="#cb4-6"></a>  <span class="co">// ...</span></span></code></pre></div>
<p>The adjustable parameters for the foam shader are the foam depth and color. The foam depth controls how much foam is shown. As the foam depth increases, the amount of foam shown increases.</p>
<h3 id="distance">Distance</h3>
<div class="sourceCode" id="cb5"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb5-1"><a href="#cb5-1"></a>  <span class="co">// ...</span></span>
<span id="cb5-2"><a href="#cb5-2"></a></span>
<span id="cb5-3"><a href="#cb5-3"></a>  vec4 positionFrom = texture(positionFromTexture, texCoord);</span>
<span id="cb5-4"><a href="#cb5-4"></a>  vec4 positionTo   = texture(positionToTexture,   texCoord);</span>
<span id="cb5-5"><a href="#cb5-5"></a></span>
<span id="cb5-6"><a href="#cb5-6"></a>  <span class="dt">float</span> depth  = (positionTo.xyz - positionFrom.xyz).y;</span>
<span id="cb5-7"><a href="#cb5-7"></a></span>
<span id="cb5-8"><a href="#cb5-8"></a>  <span class="co">// ...</span></span></code></pre></div>
<p>Compute the distance from the foreground position to the background position. Since the positions are in view (camera) space, we only need the y value since it goes into the screen.</p>
<h3 id="amount">Amount</h3>
<div class="sourceCode" id="cb6"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb6-1"><a href="#cb6-1"></a>  <span class="co">// ...</span></span>
<span id="cb6-2"><a href="#cb6-2"></a></span>
<span id="cb6-3"><a href="#cb6-3"></a>  <span class="dt">float</span> amount  = clamp(depth / foamDepth.x, <span class="dv">0</span>, <span class="dv">1</span>);</span>
<span id="cb6-4"><a href="#cb6-4"></a>        amount  = <span class="dv">1</span> - amount;</span>
<span id="cb6-5"><a href="#cb6-5"></a>        amount *= mask.r;</span>
<span id="cb6-6"><a href="#cb6-6"></a>        amount  = amount * amount / (<span class="dv">2</span> * (amount * amount - amount) + <span class="dv">1</span>);</span>
<span id="cb6-7"><a href="#cb6-7"></a></span>
<span id="cb6-8"><a href="#cb6-8"></a>  <span class="co">// ...</span></span></code></pre></div>
<p>The amount of foam is based on the depth, the foam depth parameter, and the mask value.</p>
<p align="center">
<img src="https://i.imgur.com/CDIPmin.png" alt="Easing equation." title="Easing equation.">
</p>

<div class="sourceCode" id="cb7"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb7-1"><a href="#cb7-1"></a>        <span class="co">// ...</span></span>
<span id="cb7-2"><a href="#cb7-2"></a></span>
<span id="cb7-3"><a href="#cb7-3"></a>        amount  = amount * amount / (<span class="dv">2</span> * (amount * amount - amount) + <span class="dv">1</span>);</span>
<span id="cb7-4"><a href="#cb7-4"></a></span>
<span id="cb7-5"><a href="#cb7-5"></a>        <span class="co">// ...</span></span></code></pre></div>
<p>Reshape the amount using the ease in and out easing function. This will give a lot of foam near depth zero and little to no foam near <code>foamDepth</code>.</p>
<h3 id="fragment-color">Fragment Color</h3>
<div class="sourceCode" id="cb8"><pre class="sourceCode c"><code class="sourceCode c"><span id="cb8-1"><a href="#cb8-1"></a>  <span class="co">// ...</span></span>
<span id="cb8-2"><a href="#cb8-2"></a></span>
<span id="cb8-3"><a href="#cb8-3"></a>  fragColor = mix(vec4(<span class="dv">0</span>), foamColor, amount);</span>
<span id="cb8-4"><a href="#cb8-4"></a></span>
<span id="cb8-5"><a href="#cb8-5"></a>  <span class="co">// ...</span></span></code></pre></div>
<p>The fragment color is a mix between transparent black and the foam color based on the amount.</p>
<h3 id="source">Source</h3>
<ul>
<li><a href="https://github.com/lettier/3d-game-shaders-for-beginners/blob/master/demonstration/src/main.cxx" target="_blank" rel="noopener noreferrer">main.cxx</a></li>
<li><a href="https://github.com/lettier/3d-game-shaders-for-beginners/blob/master/demonstration/shaders/vertex/base.vert" target="_blank" rel="noopener noreferrer">base.vert</a></li>
<li><a href="https://github.com/lettier/3d-game-shaders-for-beginners/blob/master/demonstration/shaders/vertex/basic.vert" target="_blank" rel="noopener noreferrer">basic.vert</a></li>
<li><a href="https://github.com/lettier/3d-game-shaders-for-beginners/blob/master/demonstration/shaders/fragment/position.frag" target="_blank" rel="noopener noreferrer">position.frag</a></li>
<li><a href="https://github.com/lettier/3d-game-shaders-for-beginners/blob/master/demonstration/shaders/fragment/foam-mask.frag" target="_blank" rel="noopener noreferrer">foam-mask.frag</a></li>
<li><a href="https://github.com/lettier/3d-game-shaders-for-beginners/blob/master/demonstration/shaders/fragment/foam.frag" target="_blank" rel="noopener noreferrer">foam.frag</a></li>
<li><a href="https://github.com/lettier/3d-game-shaders-for-beginners/blob/master/demonstration/shaders/fragment/base-combine.frag" target="_blank" rel="noopener noreferrer">base-combine.frag</a></li>
</ul>
<h2 id="copyright">Copyright</h2>
<p>(C) 2019 David Lettier <br> <a href="https://www.lettier.com">lettier.com</a></p>
<p><a href="screen-space-refraction.html"><span class="emoji" data-emoji="arrow_backward">◀️</span></a> <a href="index.html"><span class="emoji" data-emoji="arrow_double_up">⏫</span></a> <a href="#"><span class="emoji" data-emoji="arrow_up_small">🔼</span></a> <a href="#copyright"><span class="emoji" data-emoji="arrow_down_small">🔽</span></a> <a href="flow-mapping.html"><span class="emoji" data-emoji="arrow_forward">▶️</span></a></p>
  </body>
</html>
